package ch.ethz.fcl.metrobuzz.render.accessbility.view.global;

import java.awt.Color;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;

import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.data.accessibility.activity.PointOfInterest;
import ch.ethz.fcl.metrobuzz.data.transit.Stop;
import ch.ethz.fcl.metrobuzz.render.techniques.colors.MBColorMap;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Rectangle;
import ch.ethz.fcl.metrobuzz.tools.MBTools;

/**
 * Each cell represents an 500x500 meters area
 * 
 * 
 * @author Zeng Wei
 * @email zeng@arch.ethz.ch
 * 
 */
public class AccessibilityMapCell {
	// each area is represented by a rectangle
	private Rectangle area;
	private boolean areaInSg;

	// nearby stop and walk time to there
	private Map<Stop, Float> nearbyStopTimeMap;

	private StopDistanceComparator comparator;

	private Queue<Stop> nearbyStops;
	private int nearbyStopSize = 10;
	private int elementsLeft = nearbyStopSize;

	private Map<PointOfInterest, Float> accessibilePoisMap;

	private float acceValue;

	public AccessibilityMapCell(Rectangle area) {
		this.area = area;

		nearbyStopTimeMap = new HashMap<Stop, Float>();

		this.comparator = new StopDistanceComparator();
		nearbyStops = new PriorityQueue<Stop>(nearbyStopSize, comparator);

		accessibilePoisMap = new HashMap<PointOfInterest, Float>();
	}

	public void setAreaInSg(boolean areaInSg) {
		this.areaInSg = areaInSg;
	}

	public boolean isAreaInSg() {
		return areaInSg;
	}

	public void addNearbyStop(Stop stop) {
		if (elementsLeft > 0) {
			nearbyStops.add(stop);
			elementsLeft--;
		} else {
			// there is already 1 or more elements => compare to the least
			int compared = comparator.compare(stop, nearbyStops.element());
			if (compared == 1) {
				nearbyStops.remove();
				nearbyStops.add(stop);
			}
		}
		// MBTools.debug("Nearby stops size " + nearbyStops.size(), false);
	}

	public Queue<Stop> getNearbyStops() {
		return nearbyStops;
	}

	public void addStopWalkCost(Stop stop, float cost) {
		nearbyStopTimeMap.put(stop, cost);
	}

	public float getStopWalkCost(Stop stop) {
		return nearbyStopTimeMap.get(stop);
	}

	public Rectangle getArea() {
		return area;
	}

	public Point2D getCenter() {
		return new Point2D(area.getMinX() + area.getWidth() / 2, area.getMinY()
				+ area.getHeight() / 2);
	}

	public void addAccessiblePoi(PointOfInterest poi, float cost) {
		Float poiCost = accessibilePoisMap.get(poi);

		if (poiCost == null)
			accessibilePoisMap.put(poi, cost);
		else {
			float minCost = Math.min(cost, poiCost);
			accessibilePoisMap.put(poi, minCost);
		}
	}

	public Map<PointOfInterest, Float> getAccessiblePoiMap() {
		return accessibilePoisMap;
	}

	public void setAcceValue(float acceValue) {
		this.acceValue = acceValue;
	}

	public float getAcceValue() {
		return acceValue;
	}

	public void render(MBColorMap colorMap) {
		Color color = colorMap.getColor(getAcceValue(), 0, 0);
		GL11.glColor4f(color.getRed() / 255.0f, color.getGreen() / 255.0f,
				color.getBlue() / 255.0f, 1.0f);

		area.render(GL11.GL_POLYGON);
	}

	public void debug() {
		GL11.glColor4f(0.1f, 0.8f, 0.1f, 1.0f);

		area.render(GL11.GL_POLYGON);

		GL11.glColor4f(1, 0, 0, 1);

		GL11.glPointSize(6.0f);
		GL11.glBegin(GL11.GL_POINTS);
		for (Stop s : nearbyStops)
			GL11.glVertex2f(s.getX(), s.getY());
		GL11.glEnd();
	}

	private class StopDistanceComparator implements Comparator<Stop> {
		float x = area.getMinX() + area.getWidth() / 2;
		float y = area.getMinY() + area.getHeight() / 2;

		@Override
		public int compare(Stop s1, Stop s2) {
			if (MBTools.distance(x, y, s1.getX(), s1.getY()) < MBTools
					.distance(x, y, s2.getX(), s2.getY()))
				return 1;

			else if (MBTools.distance(x, y, s1.getX(), s1.getY()) > MBTools
					.distance(x, y, s2.getX(), s2.getY()))
				return -1;

			return 0;
		}
	}
}
